package dev.ece.core.cells.model.base;

import org.lwjgl.opengl.GL11;

import dev.ece.core.cells.model.AbstractUI;
import dev.ece.core.vertex.VAO;
import dev.ece.core.vertex.VBO;
import dev.ece.util.lib.IntOffset;
import dev.ece.util.lib.Rectangle;
import dev.ece.util.lib.Vector2f;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.tools.Camera;

public abstract class SquareOfThreeUI<T> extends AbstractUI<T> {

	public static final int DEFAULT_CENTER_DISTANCE = 1;
	
	private Vector3f[] vertice;
	
	private Vector2f[] uv;
	
	private VBO verticeVBO;
	
	private VBO uvVBO;
	
	private VAO vao;
	
	private float width;
	
	private float height;
	
	/**
	 * 纹理偏移量
	 */
	private Rectangle textureClipping;
	
	/**
	 * 中间区域距离边界的距离：类似于padding
	 */
	private IntOffset centerClipping;
	
	public SquareOfThreeUI(float width, float height) {
		this(new Rectangle(0, 0, 1, 1), width, height, new IntOffset(DEFAULT_CENTER_DISTANCE, DEFAULT_CENTER_DISTANCE));
	}
	
	public SquareOfThreeUI(float width, float height, IntOffset centerClipping) {
		this(new Rectangle(0, 0, 1, 1), width, height, centerClipping);
	}
	
	public SquareOfThreeUI(Rectangle textureClipping, float width, float height) {
		this(textureClipping, width, height, new IntOffset(DEFAULT_CENTER_DISTANCE, DEFAULT_CENTER_DISTANCE));
	}
	/**
	 * 
	 * @param textureClipping
	 * @param width
	 * @param height
	 * @param centerClipping 左中右或者上中下切割纹理,中间部分拉伸
	 */
	public SquareOfThreeUI(Rectangle textureClipping, float width, float height, IntOffset centerClipping) {
		if(textureClipping ==  null) {
			throw new IllegalArgumentException("参数textureClipping不能为null.");
		}
		if(centerClipping == null) {
			throw new IllegalArgumentException("参数centerClipping不能为null.");
		}
		this.width = width;
		this.height = height;
		this.textureClipping = textureClipping;
		this.centerClipping = centerClipping;
		this.init();
		this.setup();
	}
	
	protected void init() {
		final Vector2f textureSize = this.createTextureSize();
		final float hw = this.getWidth() / 2;
		final float hh = this.getHeight() / 2;
		final float tleft = this.textureClipping.left;
		final float ttop = this.textureClipping.top;
		final float tright = this.textureClipping.right;
		final float tbottom = this.textureClipping.bottom;
		
		vertice = new Vector3f[8];
		uv = new Vector2f[8];
		if(this.getCenterClipping().isVertical()) {
			//垂直
			final float top = centerClipping.head / textureSize.getY();
			final float bottom = centerClipping.foot / textureSize.getY();
			vertice[0] = new Vector3f(hw, hh, 0);
			vertice[1] = new Vector3f(-hw, hh, 0);
			
			vertice[2] = new Vector3f(hw, hh - centerClipping.head, 0);
			vertice[3] = new Vector3f(-hw, hh - centerClipping.head, 0);
			
			vertice[4] = new Vector3f(hw, - hh + centerClipping.foot, 0);
			vertice[5] = new Vector3f(-hw, - hh + centerClipping.foot, 0);
			
			vertice[6] = new Vector3f(hw, -hh, 0);
			vertice[7] = new Vector3f(-hw, -hh, 0);
			
			uv[0] = new Vector2f(tright, ttop);
			uv[1] = new Vector2f(tleft, ttop);
			
			uv[2] = new Vector2f(tright, ttop + top);
			uv[3] = new Vector2f(tleft, ttop + top);
			
			uv[4] = new Vector2f(tright, tbottom - bottom);
			uv[5] = new Vector2f(tleft, tbottom - bottom);
			
			uv[6] = new Vector2f(tright, tbottom);
			uv[7] = new Vector2f(tleft, tbottom);
			
		} else {
			//平行
			final float left = this.centerClipping.head / textureSize.getX();
			final float right = this.centerClipping.foot / textureSize.getX();
			vertice[0] = new Vector3f(-hw, hh, 0);
			vertice[1] = new Vector3f(-hw, -hh, 0);
			
			vertice[2] = new Vector3f(-hw + centerClipping.head, hh, 0);
			vertice[3] = new Vector3f(-hw + centerClipping.head, -hh, 0);
			
			vertice[4] = new Vector3f(hw - centerClipping.foot, hh, 0);
			vertice[5] = new Vector3f(hw - centerClipping.foot, -hh, 0);
			
			vertice[6] = new Vector3f(hw, hh, 0);
			vertice[7] = new Vector3f(hw, -hh, 0);
			
			uv[0] = new Vector2f(tleft, ttop);
			uv[1] = new Vector2f(tleft, tbottom);
			
			uv[2] = new Vector2f(tleft + left, ttop);
			uv[3] = new Vector2f(tleft + left, tbottom);
			
			uv[4] = new Vector2f(tright - right, ttop);
			uv[5] = new Vector2f(tright - right, tbottom);
			
			uv[6] = new Vector2f(tright, ttop);
			uv[7] = new Vector2f(tright, tbottom);
		}
	}
	
	protected void setup() {
		verticeVBO = VBO.newInstance(vertice);
		uvVBO = VBO.newInstance(uv);
		VBO.unbind();
	}
	
	@Override
	public void onInitialize() {
		vao = new VAO();
		vao.bind();
		vao.bindVertexArrayBuffer(verticeVBO, 3);
		vao.bindVertexArrayBuffer(uvVBO, 2);
		vao.finish();
		verticeVBO = null;
		uvVBO = null;
	}
	
	protected abstract Vector2f createTextureSize();
	
	@Override
	public void onRender(Camera camera, T value) {
		vao.bind();
		GL11.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, vertice.length);
	}

	public Rectangle getTextureClipping() {
		return textureClipping;
	}

	public IntOffset getCenterClipping() {
		return centerClipping;
	}

	@Override
	public float getWidth() {
		return this.width;
	}

	@Override
	public float getHeight() {
		return this.height;
	}

	@Override
	public void destroy() {
		if(vao != null) {
			vao.destroy();
		}
		vao = null;
		vertice = null;
		uv = null;
	}

}
